package soar.test.http;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.net.ssl.HttpsURLConnection;

public class App
{
    public static void main(String args[])
    {
        new App().run();
    }

    private void run()
    {
        try
        {
            String split = "========================================";
            System.out.println(split);

            urlencode();
            System.out.println(split);

            call();
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }

    private void urlencode() throws Exception
    {
        String split = "----------------------------------------";

        System.out.println("urlencode");
        System.out.println(split);

        System.out.println("encode");
        System.out.println();
        for (String s : new String[] { " ", "\t", "\n", "`", "~", "!", "@", "#",
                "$", "%", "^", "&", "*", "(", ")", "-", "_", "=", "+", "[", "{",
                "]", "}", "\\", "|", ";", ":", "'", "\"", ",", "<", ".", "?" })
        {
            System.out.println(String.format("(%s) -> (%s)", s,
                    URLEncoder.encode(s, "UTF-8")));
        }

        System.out.println(split);

        System.out.println("decode");
        System.out.println();
        for (String s : new String[] { "+", "%20", "%2B", "*", "%2A" })
        {
            System.out.println(String.format("(%s) -> (%s)", s,
                    URLDecoder.decode(s, "UTF-8")));
        }
    }

    private void call() throws Exception
    {
        String url_s = "https://www.baidu.com";
        Map<String, String> params = new HashMap<>();
        String params_s;

        params_s = params.entrySet().stream().map(x -> {
            String enc = "";
            try
            {
                enc = URLEncoder.encode(x.getValue(), "UTF-8");
            }
            catch (Exception e)
            {

            }
            return x.getKey() + "=" + enc;
        }).collect(Collectors.joining("&"));

        https("GET", url_s, params_s);
    }

    private void https(String method, String url_s, String params)
            throws Exception
    {
        String split = "----------------------------------------";

        System.out.println("http url " + method);
        System.out.println(split);

        HttpsURLConnection conn;
        if (method.equals("GET"))
        {
            if (!params.isEmpty())
            {
                if (url_s.indexOf("?") == -1)
                    url_s += "?" + params;
                else
                    url_s += "&" + params;
            }
            URL url = new URL(url_s);
            conn = (HttpsURLConnection) url.openConnection();
            conn.setRequestMethod("GET"); // 不起作用，看DoOutput
            conn.setDoOutput(false); // 缺省false
        }
        else
        {
            URL url = new URL(url_s);
            conn = (HttpsURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
        }

        set_url_connection_request(conn);
        conn.setConnectTimeout(3 * 1000);
        conn.setReadTimeout(10 * 1000);
        conn.connect();

        if (method.equals("GET"))
        {

        }
        else
        {
            byte[] b = params.getBytes();
            OutputStream out = conn.getOutputStream(); // 隐含connect()，必须在set后面
            out.write(b, 0, b.length);
            out.flush();
            out.close();
        }

        System.out.println("HeaderFields");
        System.out.println();
        conn.getHeaderFields().forEach((k, v) -> {
            System.out.println(k + ":");
            v.forEach(x -> {
                System.out.println("\t" + x);
            });
        });
        System.out.println(split);

        String output = read_url_connection_response(conn);
        // System.out.println(output);

        FileWriter fwriter = new FileWriter("output_https.txt");
        fwriter.write(output);
        fwriter.close();

        // FileOutputStream fout = new FileOutputStream("output_https_buf.txt");
        // fout.write(buf);
        // fout.close();
    }

    private void set_url_connection_request(HttpURLConnection conn)
    {
        conn.setRequestProperty("User-Agent",
                "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36");
        conn.setRequestProperty("Content-type",
                "application/x-www-form-urlencoded; charset=utf-8");
        conn.setRequestProperty("Accept-Language",
                Locale.getDefault().toString());
        conn.setRequestProperty("Accept-Charset", "UTF-8");
    }

    private String read_url_connection_response(HttpURLConnection conn)
            throws Exception
    {
        InputStream in = conn.getInputStream();
        int content_length = conn.getContentLength();
        if (content_length < 0)
            content_length = 2 * 1024 * 1024;
        byte[] buf = new byte[content_length];
        int size = 0;
        while (true)
        {
            int n = in.read(buf, size, content_length - size);
            if (n == -1)
                break;
            size += n;
        }
        System.out.println("ContentLength: " + conn.getContentLength());
        System.out.println("size: " + size);

        String charset = conn.getContentEncoding();
        if (charset == null)
        {
            String content_type = conn.getContentType();
            if (content_type != null)
            {
                Pattern pattern = Pattern
                        .compile(".*charset *= *([A-Za-z_\\-0-9]+).*");
                Matcher matcher = pattern.matcher(content_type);
                if (matcher.matches())
                {
                    charset = matcher.group(1);
                }
                else
                {
                    charset = "UTF-8";
                }
            }
            else
            {
                charset = "UTF-8";
            }
        }
        return new String(buf, 0, size, charset);
    }
}
